/**
* @author Ucar Sahin
*
* 03.06.2011
* ProtocolController.java
* 
*/

package at.fhv.easyDietWeb.server.controller.useCase;

import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import at.fhv.easyDietWeb.server.controller.DatabaseController;
import at.fhv.easyDietWeb.server.controller.DomainController;
import at.fhv.easyDietWeb.server.util.DateValidator;
import at.fhv.easyDietWeb.shared.db.bls.Dimension;
import at.fhv.easyDietWeb.shared.db.bls.Food;
import at.fhv.easyDietWeb.shared.db.diet.Meal;
import at.fhv.easyDietWeb.shared.db.diet.MealLine;
import at.fhv.easyDietWeb.shared.db.diet.MealType;
import at.fhv.easyDietWeb.shared.db.diet.NutritionalJournal;
import at.fhv.easyDietWeb.shared.db.masterData.Patient;
import at.fhv.easyDietWeb.shared.exception.database.MissingSearchKeyException;
import at.fhv.easyDietWeb.shared.exception.database.NoSearchResultException;
import at.fhv.easyDietWeb.shared.exception.domain.InvalidInputException;
import at.fhv.easyDietWeb.shared.exception.domain.PlanSaveFailedException;
import at.fhv.easyDietWeb.shared.exception.useCase.CannotSaveNutritionalJournalException;
import at.fhv.easyDietWeb.shared.exception.useCase.IncorrectInputException;
import at.fhv.easyDietWeb.shared.exception.useCase.InvalidNutritionalJournalException;
import at.fhv.easyDietWeb.shared.exception.useCase.NoFoodFoundException;
import at.fhv.easyDietWeb.shared.exception.useCase.NoMealTypeFoundException;
import at.fhv.easyDietWeb.shared.exception.useCase.NoPatientFoundException;
import at.fhv.easyDietWeb.shared.util.ProtocolData;
import at.fhv.easyDietWeb.shared.util.wrappers.DayWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.FoodWrapper;
import at.fhv.easyDietWeb.shared.util.wrappers.MealLineWrapper;

/**
 * a controller for the use case "Protokoll anlegen - Web"
 * @author Spiegel Philipp
 *
 */
public class ProtocolController
{	
	/**
	 * returns Strings of the names of all meal types
	 * @return names of all meal types
	 */
	public List<String> getMealTypes()
	{
		List<String> mealTypes = null;
		List<MealType> mealTypesFromDB = null;
		
		try
		{
			//load meal types from the database and get their names
			mealTypes = new LinkedList<String>();
			mealTypesFromDB = DatabaseController.getInstance().getMealTypes();
			
			for (MealType m : mealTypesFromDB)
			{
				mealTypes.add(m.getDescription());
			}
		} 
		catch (NoSearchResultException e)
		{
			e.printStackTrace();
		}
		
		return mealTypes;
	}

	/**
	 * validates if the new protocol has no date conflicts with older ones
	 * @param from from date
	 * @param until until date
	 * @param id id
	 * @return true, if the time span is ok
	 */
	public boolean validateDates(Date from, Date until, int id)
	{
		DateValidator dV = new DateValidator();
		
		return dV.validateDates(from, until, id);
	}
	
	/**
	 * returns a list of all food names from the bls, which corresponds to a pattern
	 * @param name name as pattern to search for; this String is at the beginning followed by a wildcard
	 * @return list of all found food names
	 * @throws NoFoodFoundException 
	 * @throws IncorrectInputException 
	 */
	public List<FoodWrapper> getFoodList(String name) throws NoFoodFoundException, IncorrectInputException
	{
		List<FoodWrapper> foodList = null;
		List<Food> foodListFromDB = null;
		
		try
		{
			//get the foods from the db
			foodList = new LinkedList<FoodWrapper>();
			foodListFromDB = DatabaseController.getInstance().getFoodListForNutritinalJournal(name);
			
			//get the names of the food
			for (Food f : foodListFromDB)
			{
				foodList.add(new FoodWrapper(f.getName(), f.getblsCode()));
			}
			return foodList;
		}
		catch (NoSearchResultException e)
		{
			return null;
		} 
		catch (MissingSearchKeyException e)
		{
			return null;
		}
	}

	/**
	 * loads all known units from the database
	 * @return all known units
	 */
	public List<String> loadUnits()
	{
		List<String> units = null;
		List<Dimension> unitsFromDB = null;
		
		try
		{
			//load the units from the database
			units = new LinkedList<String>();
			unitsFromDB = DatabaseController.getInstance().loadUnits();
			
			//get the names
			for (Dimension d : unitsFromDB)
			{
				units.add(d.getDescription());
			}
		}
		catch (NoSearchResultException ex)
		{
			ex.printStackTrace();
		}
		
		return units;
	}
	
	/**
	 * saves the Protocol on the Database
	 * 
	 * @param data a wrapper object, which contains the input of the user
	 * @param patientId id of the patient
	 * @throws NoPatientFoundException 
	 * @throws NoMealTypeFoundException 
	 * @throws NoFoodFoundException 
	 * @throws InvalidNutritionalJournalException 
	 * @throws CannotSaveNutritionalJournalException 
	 */
	public void saveProtocol(ProtocolData data, int patientId) throws NoPatientFoundException, NoMealTypeFoundException, NoFoodFoundException, InvalidNutritionalJournalException, CannotSaveNutritionalJournalException {
		
		NutritionalJournal nutritionalJournal = new NutritionalJournal();
		Patient patient = null;
		try {
			patient = DatabaseController.getInstance().getPatient(patientId);
		} catch (NoSearchResultException e) {
			throw new NoPatientFoundException();
		}
		
		nutritionalJournal.setPatient(patient);
		nutritionalJournal.setStartDate(data.getFromDate());
		nutritionalJournal.setEndDate(data.getUntilDate());
		
		List<Meal> meals = new LinkedList<Meal>();
		List<MealLine> mealLines = new LinkedList<MealLine>();
		List<Meal> tempMeals = new LinkedList<Meal>();		
		
		for (DayWrapper day : data.getDays()){
			List<MealType> mealTypes = new LinkedList<MealType>();
			
			for (MealLineWrapper mealLine : day.getMeals()){								
				try {
					MealType mt = DatabaseController.getInstance().getMealType(mealLine.getMeal());
					if (!mealTypes.contains(mt)){
						mealTypes.add(mt);
					}
				} catch (NoSearchResultException e) {
					throw new NoMealTypeFoundException();
				}
			}
			
			for (MealType mt : mealTypes){
				Meal meal = new Meal();
				meal.setNutritionalJournal(nutritionalJournal);
				meal.setMealType(mt);
				
				int dayNr = Integer.valueOf(day.getDay().substring(4));
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(data.getFromDate());
				calendar.add(Calendar.DAY_OF_MONTH, dayNr);
				Date date = calendar.getTime();	
				
				meal.setDay(date);
				tempMeals.add(meal);
				meals.add(meal);
			}
			
			List<MealLineWrapper> mealLinesW = day.getMeals();
			
			for (MealLineWrapper mealLineW : mealLinesW)
			{
				Food food = null;
				try
				{
					food = DatabaseController.getInstance().getFood(mealLineW.getFood().getBLSCode());
				}
				catch (NoSearchResultException e)
				{
					throw new NoFoodFoundException();
				}
				
				Meal meal = null;
				
				for (Meal m : tempMeals)
				{
					if (mealLineW.getMeal().equals(m.getMealType().getDescription()))
					{
						meal = m;
						break;
					}
				}
				
				MealLine mealLine = new MealLine();
				mealLine.setMeal(meal);
				mealLine.setFood(food);
				mealLine.setPortion(Double.valueOf(mealLineW.getAmount()));
				
				mealLines.add(mealLine);
				
			}
			
			tempMeals.clear();
		}
		
		try 
		{
			DomainController.getInstance().saveNutritionalJournal(nutritionalJournal, meals, mealLines);
		}
		catch (InvalidInputException e) 
		{
			throw new InvalidNutritionalJournalException();
		}
		catch (PlanSaveFailedException e) 
		{
			throw new CannotSaveNutritionalJournalException();
		}
	}
}
